{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import wave\n",
    "import numpy as np\n",
    "import pylab as plt\n",
    "from scipy.signal import firwin\n",
    "%matplotlib inline\n",
    "np.set_printoptions(precision=4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "cMatrix = [\n",
    "-8.0637536579e-19, -1.3147051387e-03,  7.6108568498e-03, -2.5651021426e-02,  6.8424554212e-02, -1.7058731625e-01,  6.2151763175e-01,  6.2151763175e-01, -1.7058731625e-01,  6.8424554212e-02, -2.5651021426e-02,  7.6108568498e-03, -1.3147051387e-03, -6.7593229191e-19, \n",
    " 4.2231062201e-04, -7.3849128016e-03,  2.5640816965e-02, -6.6353440284e-02,  1.5092479216e-01, -3.2077802693e-01,  1.4888931696e+00, -1.4427957650e+00,  2.3570009308e-01, -9.4794181655e-02,  4.2345341839e-02, -1.6409871256e-02,  4.5783425462e-03,  1.1331118064e-05, \n",
    "-2.1039703946e-04,  2.5136661122e-02, -1.0872200064e-01,  3.2013962622e-01, -7.8318559530e-01,  1.5750766194e+00, -1.4888752992e+00,  1.8849828001e-01,  3.9656040521e-01, -1.5899187363e-01,  4.0735786821e-02, -1.3418581423e-03, -4.7902599462e-03, -3.0094962531e-05, \n",
    "-1.5266187212e-03, -8.8261863321e-03,  4.9819305402e-02, -1.5971061030e-01,  3.9324893267e-01, -4.6219364451e-01, -1.7870407362e-05,  4.6219253697e-01, -3.9324862783e-01,  1.5971047964e-01, -4.9819250384e-02,  8.8261674102e-03,  1.5266225387e-03,  1.8763844467e-05,     \n",
    "]\n",
    "NTAPS = 14\n",
    "ORDER = 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def sample_to_int(data):\n",
    "        d = int.from_bytes(data, byteorder='little', signed=True)\n",
    "        return d\n",
    "\n",
    "def int_to_sample(data):\n",
    "        d = int(data)\n",
    "        return d.to_bytes(3, byteorder='little', signed=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "out_sample = 0\n",
    "sample_inc = 1.001"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "fname = \"sine.wav\"\n",
    "f = wave.open(fname, 'rb')\n",
    "\n",
    "f_out = wave.open(\"wave_out.wav\", \"wb\")\n",
    "f_out.setframerate(48000)\n",
    "f_out.setsampwidth(3)\n",
    "f_out.setnchannels(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "audio_delay_line = np.zeros(NTAPS)\n",
    "delay_line_sample = -NTAPS"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def c(ixTap, ixPower):\n",
    "    return cMatrix[ixPower * (NTAPS) + ixTap]*0.99"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def get_imp(tap, frac):\n",
    "    horner_sum = c(tap, ORDER)\n",
    "    for i in range(ORDER-1, -1, -1,):\n",
    "        horner_sum *= frac\n",
    "        horner_sum += c(tap, i)\n",
    "    return horner_sum"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def get_c(frac):\n",
    "    return [get_imp(i, frac) for i in range(NTAPS)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def process_sample(frac):\n",
    "    fir_c = get_c(frac)\n",
    "    v = np.sum(audio_delay_line*fir_c)\n",
    "    return v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "while(True):\n",
    "    data = f.readframes(1)\n",
    "    audio_delay_line = np.roll(audio_delay_line, 1)\n",
    "    audio_delay_line[0] = sample_to_int(data)\n",
    "    delay_line_sample += 1\n",
    "    if(len(data)==0):\n",
    "        break\n",
    "    while(out_sample < delay_line_sample):\n",
    "        frac = out_sample % 1\n",
    "        v = process_sample(frac)\n",
    "        f_out.writeframes(int_to_sample(v))\n",
    "        out_sample += sample_inc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "f.close()\n",
    "f_out.close()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
